package tool

import (
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"math/rand"
	"strings"
	"time"
)

/**
为什么用96位随机数
可参见OAuth2TokenFormat类，即访问令牌access_token支持如下两种类型（原来不可配置且只支持JWT）：

    SELF_CONTAINED（默认） - 自签JWT类型（包含claim信息如sub、scopes等内容）
    REFERENCE - 引用类型（Support opaque access tokens），即生成96位随机字符串，具体claim信息存储在DB中

版权声明：本文为CSDN博主「罗小爬EX」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。
原文链接：https://blog.csdn.net/luo15242208310/article/details/124268007
*/

// CreateAuthorizeState 创建授权码状态
func CreateAuthorizeState() string {
	return randomString(8)
}

// CreateAuthorizeCode 创建授权码，存这个随机。用这个查，需要带过期时间
func CreateAuthorizeCode() string {
	return randomString(96)
}

// CreateRefreshToken 创建刷新token，存这个随机，用这个字符串查，需要带过期时间
func CreateRefreshToken() string {
	return randomString(96)
}

// CreateOpenId 创建OpenId
func CreateOpenId() string {
	return randomTik()
}

// CreateClientId 创建随机的clientId
func CreateClientId() string {
	return randomString(12)
}
func CreateClientSecret() string {
	return randomString(16)
}

// CreateToken 创建token
func CreateToken(audClientId, subUsername, issUri string, scope []string, expExpiresTime int64) (token string) {
	token = createJwt(audClientId, subUsername, issUri, scope, expExpiresTime)
	return
}

// ParseToken 解析token
func ParseToken(token string) (*JClaims, error) {
	return parseJwt(token)
}

// VerifyPKCESHA256 对比sha256，是Proof Key for Code Exchange模式下的
func VerifyPKCESHA256(encrypted, original string) bool {
	// 解开base64
	encrypt256, err := base64.StdEncoding.DecodeString(encrypted)
	orig, err := base64.StdEncoding.DecodeString(original)
	if err != nil {
		return false
	}
	// 重新加密原始数据，需要用hex转换为进制
	orig256 := sha256.Sum256(orig)
	orig256b := hex.EncodeToString(orig256[:])
	// 对比
	if string(encrypt256) == orig256b {
		return true
	} else {
		return false
	}
}

// 随机字符串规则
const randString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"

// randomString 生成随机字符串，时间戳模式，类似crypto/rand包里的
func randomString(length int) string {
	// 随机数字符串规则
	str := []byte(randString)
	// 返回
	var result []byte
	// 随机数种子
	rand.Seed(time.Now().UnixNano() + int64(rand.Intn(100)))
	for i := 0; i < length; i++ {
		// 添加到结果里，随机字符串规则中某个种子字符
		result = append(result, str[rand.Intn(len(str))])
	}
	return string(result)
}

// randomTik 随机tik风格token
func randomTik() string {
	// 去掉后面数字，有点影响性能，但不经常调用
	var randNotNum []byte
	str := []byte(randString)
	for i, v := range str {
		if i < 51 {
			randNotNum = append(randNotNum, v)
		}
	}
	/**
	前缀头部，只会是两个字母
	*/
	head := make([]byte, 2)
	rand.Seed(time.Now().UnixNano() + int64(rand.Intn(100)))
	head[0] = randNotNum[rand.Intn(len(randNotNum))]
	head[1] = randNotNum[rand.Intn(len(randNotNum))]
	// 返回
	return string(head) + "_" + randomString(14) + "_" + randomString(16) + "__"
}

// CalculateExpiresTime 计算过期的时间戳
func CalculateExpiresTime(expiresCount int64) (createTime int64, expiresTime int64) {
	createTime = time.Now().Unix()
	expiresTime = time.Now().Unix() + expiresCount
	return
}

// IsExpired 是否过期
func IsExpired(futureTime int64) bool {
	nowTime := time.Now().Unix()
	if futureTime > nowTime {
		return true
	}
	return false
}

// StringListBuild 构建字符串列表用，例如：value1,value2,value3...
func StringListBuild(str []string) (strBuild string) {
	for i, v := range str {
		if i == len(str)-1 {
			strBuild += v
		} else {
			strBuild += v + ","
		}
	}
	return
}

// StringListDestroy 解构字符串列表
func StringListDestroy(sb string) []string {
	return strings.Split(sb, ",")
}
